﻿using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Text;

namespace UDS.Management
{
    public enum Severity
    {
        Information,
        Warning,
        Error
    }

    public class Logger
    {
        private static readonly object s_locker = new object();
        private static InternalLogger s_logger;

        /// <summary>
        /// The logger will create a new file per day.
        /// </summary>
        private class InternalLogger : IDisposable
        {
            private Stream _fs;
            public DateTime _timeCreated = DateTime.Now;

            public InternalLogger()
            {
                string dir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
                int numAttempts = 1;
                string traceFile = Path.Combine(dir, string.Format("{0:yyyy-MM-dd}.log", _timeCreated));
                do
                {
                    try
                    {
                        // Open the new trace file now, and hold the handle until the program was terminated!
                        // In this way, we can ensure that only 1 process can access this file.
                        _fs = new FileStream(traceFile, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.Read);
                        break;
                    }
                    catch (IOException)
                    {
                        // Failed to create the trace file. Maybe it already exists.
                        // Let's try another file.
                    }

                    traceFile = Path.Combine(dir, string.Format("{0:yyyy-MM-dd}-{1:00}.log", _timeCreated, numAttempts++));
                } while (true);

                Trace.Listeners.Clear();

                TextWriter tw = new StreamWriter(_fs, Encoding.UTF8);
                TextWriterTraceListener listener = new TextWriterTraceListener(tw, "Default Trace Listener");
                Trace.Listeners.Add(new ConsoleTraceListener());
                Trace.Listeners.Add(listener);
                Trace.AutoFlush = true;
            }

            public void Dispose()
            {
                if (_fs != null)
                {
                    _fs.Dispose();
                }
            }
        }

        public static void WriteLine(string message)
        {
            WriteLine(message, Severity.Information);
        }

        public static void WriteLine(string message, Severity severity)
        {
            // Ensure the logger is initialized
            if (s_logger == null)
            {
                lock (s_locker)
                {
                    if (s_logger == null)
                    {
                        s_logger = new InternalLogger();
                    }
                }
            }

            // Do we need to create a new logger file?
            if (DateTime.Now.Day != s_logger._timeCreated.Day)
            {
                InternalLogger oldLogger;
                lock (s_locker)
                {
                    oldLogger = s_logger;
                    s_logger = new InternalLogger();
                }

                // Dispose the old logger now
                oldLogger.Dispose();
            }

            Trace.WriteLine(string.Format("[{0:yyyy-MM-dd HH:mm:ss}] {1} {2}", DateTime.Now, severity,  message));
        }
    }
}
